package com.iwdnb.gkgz.ui.controller;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.date.DateUtil;
import com.iwdnb.bmnf.common.excel.core.ExcelService;
import com.iwdnb.bmnf.common.model.result.Result;
import com.iwdnb.gkgz.application.model.request.AddStrategyTradeStockDataRequest;
import com.iwdnb.gkgz.application.service.StockRangeService;
import com.iwdnb.gkgz.common.enums.RangeTypeEnums;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.model.dto.StockRangeApproximateData;
import com.iwdnb.gkgz.common.model.dto.StockRangeDTO;
import com.iwdnb.gkgz.common.model.dto.StockRangeScopeDTO;
import com.iwdnb.gkgz.common.quota.MovingAverage;
import com.iwdnb.gkgz.common.utils.BigDecimalUtils;
import com.iwdnb.gkgz.common.utils.StockRangeUtils;
import com.iwdnb.gkgz.common.utils.StockUtils;
import com.iwdnb.gkgz.infrastructure.dao.repo.StockDayDataRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 波段
 */
@RestController
@RequestMapping("/api/stock/range")
@Slf4j
public class StockRangeController {

    @Autowired
    private StockRangeService stockRangeService;
    @Autowired
    private StockDayDataRepository stockDayDataRepository;
    @Autowired
    private ExcelService excelService;

    /**
     * 获取股票波段数据
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryStockRangeList")
    public Result<List<StockRangeDTO>> queryStockRangeList(String code) {
        return Result.getSuccessResult(stockRangeService.queryStockRangeList(code));
    }

    /**
     * 获取股票波段数据
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryReorganizeStockRangeList")
    public Result<List<StockRangeApproximateData>> queryReorganizeStockRangeList(String code, String date) {
        List<StockRangeDTO> stockRangeDTOList = stockRangeService.queryStockRangeList(code);
        List<StockRangeApproximateData> stockRangeApproximateDataList = StockRangeUtils.reorganizeStockRangeList(
            stockRangeDTOList, date);
        return Result.getSuccessResult(stockRangeApproximateDataList);
    }

    /**
     * 获取指定日期之前1年股票价格数据
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryStockRangeScopeBeforeDate")
    public Result<StockRangeScopeDTO> queryStockRangeScopeList(String code, String date) {
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAll(code);
        return Result.getSuccessResult(StockUtils.getRangeScopeByDateRange(stockDayDataList, date));
    }

    /**
     * 获取指定日期之前1年股票波段
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryStockRangeListBeforeDate")
    public Result<List<StockRangeDTO>> queryStockRangeListBeforeDate(String code, String date) {
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAll(code);
        List<StockRangeDTO> rangeDTOList = StockRangeUtils.calculateStockRange(stockDayDataList);
        StockDayData stockDayData=StockUtils.getStockDayData(stockDayDataList,date);
        return Result.getSuccessResult(StockRangeUtils.getRangeListByDateRange(rangeDTOList, stockDayData));
    }

    /**
     * 获取指定日期之前1年股票波段
     *
     * @param codes
     * @return
     */
    @GetMapping(value = "/queryAllStockRangeLowDate")
    public Result<Void> queryAllStockRangeLowDate(String codes) {
        String[] codeArray = codes.split(",");
        for (String code : codeArray) {
            queryAllStockRangeLowDateByCode(code);
        }
        return Result.getSuccessResult(null);
    }

    public List<String> queryAllStockRangeLowDateByCode(String code) {
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAll(code);
        List<StockRangeDTO> rangeDTOList = StockRangeUtils.calculateStockRange(stockDayDataList);
        List<String> dateList = new ArrayList<>();
        int matchIndex = 200;
        int upCount = 0;
        int downCount = 0;
        int stableCount = 0;
        int period = 20;
        MovingAverage.calculateEMA(stockDayDataList, period);
        BigDecimal FIFTEEN = new BigDecimal(15);
        BigDecimal NEG_FIVE = new BigDecimal(-5);

        for (int i = 250; i < stockDayDataList.size(); i++) {
            if (i - matchIndex < 40) {
                continue;
            }
            StockDayData data = stockDayDataList.get(i);
            String date = data.getDate();
            //在20日均线下方
            BigDecimal twentyAvg = StockUtils.getAveragePrice(data, period);
            if (BigDecimalUtils.isGt(data.getClosePrice(), twentyAvg)) {
                continue;
            }
            //2个月下跌超过15%
            String beginDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.parseDate(date), -50));
            StockRangeScopeDTO twoMonthRangeScope = StockUtils.getRangeScopeByDateRange(stockDayDataList, beginDate,
                date);
            BigDecimal highRate = BigDecimalUtils.subStractAndDividePrecent(twoMonthRangeScope.getHighPrice(),
                data.getClosePrice());
            if (BigDecimalUtils.isLe(highRate, FIFTEEN)) {
                continue;
            }
            BigDecimal lowRate = BigDecimalUtils.subStractAndDividePrecent(twoMonthRangeScope.getLowPrice(),
                data.getClosePrice());
            if (BigDecimalUtils.isLe(lowRate, NEG_FIVE)) {
                continue;
            }
            StockRangeDTO lowRange = StockRangeUtils.getMatchLowRangeByDateRange(data, rangeDTOList);
            if (Objects.isNull(lowRange)) {
                //log.info("{}-{}-未匹配上波段低点", code, data.getDate());
                continue;
            }
            dateList.add(data.getDate());
            log.info("{}-匹配上波段低点,日期:{},{},价格:{}-{}", code, lowRange.getEndDate(), data.getDate(),
                lowRange.getLowPrice(), data.getClosePrice());
            matchIndex = i;
            //计算是否向上突破
            String rangeType = calculateOutRange(code, data, lowRange, stockDayDataList);
            if (RangeTypeEnums.UP.equalsCode(rangeType)) {
                upCount++;
            } else if (RangeTypeEnums.DOWN.equalsCode(rangeType)) {
                downCount++;
            } else {
                stableCount++;
            }
        }
        log.info("{}-向上突破{}次，向下突破{}次，横盘{}次", code, upCount, downCount, stableCount);
        return dateList;
    }

    private String calculateOutRange(String code, StockDayData stockDayData, StockRangeDTO lowRange,
        List<StockDayData> stockDayDataList) {
        stockDayDataList = StockUtils.getStockDayDataListAfterDate(stockDayDataList, stockDayData.getDate(), 40);
        stockDayDataList.add(0, stockDayData);
        BigDecimal lowPrice = stockDayData.getClosePrice();
        BigDecimal FIVE = new BigDecimal(10);

        BigDecimal NEG_FIVE = new BigDecimal(-10);
        for (int i = 0; i < stockDayDataList.size(); i++) {
            StockDayData data = stockDayDataList.get(i);
            BigDecimal rate = BigDecimalUtils.subStractAndDividePrecent(data.getClosePrice(), lowPrice);
            if (BigDecimalUtils.isGe(rate, FIVE)) {
                //log.info("{}-第{}天向上突破,前期波段高点:{}", data.getDate(), (i + 1), lowRange.getHighPrice());
                StockUtils.caculateAfterDaysProfit(code, stockDayData.getDate(), stockDayDataList, 40);
                return RangeTypeEnums.UP.getCode();
            }
            if (BigDecimalUtils.isLe(rate, NEG_FIVE)) {
                //log.info("{}-第{}天向下突破", data.getDate(), (i + 1));
                StockUtils.caculateAfterDaysProfit(code, stockDayData.getDate(), stockDayDataList, 40);
                return RangeTypeEnums.DOWN.getCode();
            }
        }
        //log.info("{}-未来40天保持横盘", stockDayData.getDate());
        StockUtils.caculateAfterDaysProfit(code, stockDayData.getDate(), stockDayDataList, 40);
        return RangeTypeEnums.STABLE.getCode();
    }

    /**
     * 获取指定日期之前1年与当前股价匹配股票低点波段
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/getMatchLowRangeByDateRange")
    public Result<StockRangeDTO> getMatchLowRangeByDateRange(String code, String date) {
        List<StockDayData> stockDayDataList = stockDayDataRepository.queryAll(code);
        List<StockRangeDTO> rangeDTOList = StockRangeUtils.calculateStockRange(stockDayDataList);
        StockDayData stockDayData = StockUtils.getStockDayData(stockDayDataList, date);
        return Result.getSuccessResult(StockRangeUtils.getMatchLowRangeByDateRange(stockDayData, rangeDTOList));
    }

    /**
     * 获取股票波段数据
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/exportStockRangeList")
    public void exportStockRangeList(String code, HttpServletResponse response) {
        List<StockRangeDTO> stockRangeDTOList = stockRangeService.queryStockRangeList(code);
        try {
            excelService.exportExcel(stockRangeDTOList, response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 是否为底部价格
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/isLowPrice")
    public Result<Boolean> isLowPrice(String code, String date) {
        return Result.getSuccessResult(stockRangeService.isLowPrice(code, date));
    }

    /**
     * 查询全部低价日期
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryLowPriceDateList")
    public Result<List<String>> queryLowPriceDateList(String code) {
        return Result.getSuccessResult(stockRangeService.queryLowPriceDateList(code));
    }

    /**
     * 查询全部低价日期
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryBollingLowPriceDateList")
    public Result<List<String>> queryBollingLowPriceDateList(String code) {
        return Result.getSuccessResult(stockRangeService.queryBollingLowPriceDateList(code));
    }

    /**
     * 查询全部低价日期
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryBollingAndLowPriceDateList")
    public Result<List<String>> queryBollingAndLowPriceDateList(String code) {
        return Result.getSuccessResult(stockRangeService.queryBollingAndLowPriceDateList(code));
    }

    /**
     * 查询全部低价日期
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryBollingAndLowPriceAndBiasDateList")
    public Result<List<String>> queryBollingAndLowPriceAndBiasDateList(String code) {
        List<String> list = stockRangeService.queryBollingAndLowPriceAndBiasDateList(code);
        return Result.getSuccessResult(list);
    }

    /**
     * 查询全部高价日期
     *
     * @param code
     * @return
     */
    @GetMapping(value = "/queryBollingAndHighPriceAndBiasDateList")
    public Result<List<String>> queryBollingAndHighPriceAndBiasDateList(String code) {
        List<String> list = stockRangeService.queryBollingAndHighPriceAndBiasDateList(code);
        return Result.getSuccessResult(list);
    }

    /**
     * 查询今天低价的全部股票信息
     *
     * @return
     */
    @GetMapping(value = "/queryLowStockList")
    public Result<List<String>> queryLowStockList(String date) {
        List<String> list = stockRangeService.queryLowStockList(date);
        return Result.getSuccessResult(list);
    }

    /**
     * 查询今天全部可买的股票信息
     *
     * @return
     */
    @GetMapping(value = "/queryTodayBuyStockList")
    public Result<List<String>> queryTodayBuyStockList(String date) {
        List<String> list = stockRangeService.queryTodayBuyStockList(date);
        return Result.getSuccessResult(list);
    }

    /**
     * 获取股票的趋势信息
     *
     * @return
     */
    @GetMapping(value = "/getTrend")
    public Result<String> getTrend(String code, String date, int period) {
        return Result.getSuccessResult(stockRangeService.getTrend(code, date, period));
    }

    /**
     * 获取股票趋势上升时20日回落后反弹买点日期数据
     *
     * @return
     */
    @GetMapping(value = "/queryTrendTwentyBackDateList")
    public Result<List<String>> queryTrendTwentyBackDateList(String code) {
        return Result.getSuccessResult(stockRangeService.queryTrendTwentyBackDateList(code));
    }

    /**
     * 全部股票20日回调买入策略交易回测
     *
     * @param request
     * @return
     */
    @PostMapping(value = "/doAllTrendTwentyBackTest")
    public Result<Void> doAllTrendTwentyBackTest(@RequestBody AddStrategyTradeStockDataRequest request) {
        stockRangeService.doAllTrendTwentyBackTest(request);
        return Result.getSuccessResult(null);
    }

}
